
const url = require('url')
const methods = require('methods')
const Layer = require('./layer')
const Route = require('./route')

function Router() {
    let router = function (req, res, next) {
        router.handle(req, res, next) // 重新去匹配路由   此时用户req.pathname 为 /user/add  此router下layer为 /add
    }
    router.__proto__ = proto  // 确保this指向
    router.stack = [] // 存url-layer
    router.events = {}
    // this.stack = []
    // return function(req,res,next){ // 错误写法 fn return 引用类型时 内部的this会指向return的值
    // }
    return router
}
let proto = {}

proto.route = function (path) { // 创建一个route实例
    let route = new Route(path)
    let layer = new Layer(path, route.dispatch.bind(route))
    layer.route = route
    this.stack.push(layer)
    return route
}

proto.use = function (...args) { // 创建一个中间件
    let path = '/'
    let handles = []
    if (typeof args[0] === 'function') {
        handles = [...args]
    } else {
        path = args[0]
        handles = args.slice(1)
    }
    handles.forEach(handler => {
        let layer = new Layer(path, handler)
        layer.route = undefined
        this.stack.push(layer)
    })
}


methods.forEach(method => {
    proto[method] = function (path, ...handlers) {
        let route = this.route(path)
        route[method](handlers)
        // console.log(this.stack)  2 层 layer
        // console.log(route)
        // this.stack.push({
        //     method: 'get',
        //     path,
        //     handler
        // })
    }
})


proto.param = function (key, fn) {  //  路由参数拦截中间件  收集fn
    if (this.events[key]) {
        this.events[key].push(fn)
    } else {
        this.events[key] = [fn]
    }
}

proto.handle_params = function (req, res, out, layer) {  // 路由参数拦截  处理fn
    let keys = layer.keys.map(v => v.name) // [id name]
    if (!keys?.length) return out()  // 没有参数路由
    let index = 0;
    let fns;
    let key;
    let i = 0;
    const next = () => {
        if (index === keys.length) return out()
        key = keys[index++]
        fns = this.events[key]  // {id:  [fn fn],name: [fn fn]}
        if (fns) {
            processCallback()
        } else {
            next()
        }

    }

    next()
    function processCallback() {
        let fn = fns[i++]
        if (!fn) {
            i = 0
            next()
        } else {
            fn(req, res, processCallback, layer.params[key], key)
        }
    }


}

proto.handle = function (req, res, done) {  // 遍历stack 匹配layer 命中时调用layer.route.dispatch  并将下一个layer当做next传递下去
    const { pathname } = url.parse(req.url)
    const method = req.method.toLowerCase()
    // for (let i = 0; i < this.stack.length; i++) {
    //     const { path, method, handler } = this.stack[i]
    //     if (pathname === path && method === req.method.toLowerCase()) {
    //         return handler(req, res)
    //     }
    // }
    // return done()
    let i = 0
    let removePath = ''

    const next = (err) => {
        if (i === this.stack.length) return done() // 没有匹配到 走done
        if (removePath) {// 下一个next时 将原来的 /user 拼接进去
            console.log('removePath====', removePath, pathname)
            req.url = removePath + req.url
            removePath = ''
        }
        let layer = this.stack[i++]
        if (err) {
            if (!layer.route) {  // 中间件
                if (layer.handler.length === 4) {
                    layer.handler(err, req, res, next)
                } else {
                    next(err)
                }
            } else {
                next(err)
            }
        } else {
            if (layer.match(pathname)) {
                req.params = layer.params
                if (!layer.route) { // 中间件
                    if (layer.handler.length === 4) { // 没有出错时不走 错误处理中间件
                        next()
                    } else {
                        if (layer.url !== '/') { // 将 /user 截取并保存
                            removePath = layer.path
                            req.url = req.url.slice(removePath.length)
                        }
                        layer.handle_request(req, res, next) // 相当于 layer.route.dispatch
                    }

                } else {
                    if (layer.route.methods[method]) { //  当前route中包含此种请求方式时 才会next
                        this.handle_params(req, res, () => {
                            layer.handle_request(req, res, next) // 相当于 layer.route.dispatch
                        }, layer)
                    } else {
                        next()
                    }
                }

            } else {
                next()
            }
        }

    }
    next()
}


module.exports = Router